package v1

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"maya-service/bll"
	"maya-service/bll/weixin"
	log "maya-service/collector/logger"
	"maya-service/config"
	"maya-service/constant"
	"maya-service/model"
	"maya-service/model/po"
	"maya-service/server/web/middleware"
	"maya-service/store/redis"
	"maya-service/utils"
	"maya-service/utils/request"
	"sort"
	"strings"
	"time"
)

var Notify = &notify{}

func init() {
	RegisterRouter(Notify)
}

type notify struct{}

// Init
func (a *notify) Init(r *gin.RouterGroup) {
	g := r.Group("/notify", middleware.ApiKeyCheck())
	{
		// 登录
		g.POST("/vip_charge", a.vipChargeNtf)
	}

	g1 := r.Group("/event", middleware.ApiKeyCheck())
	{
		// 登录
		g1.POST("/notify", a.eventNotify)
	}

	g2 := r.Group("/wx")
	{
		// 登录
		g2.GET("/notify", a.wxNotify)
		// 登录
		g2.POST("/notify", a.wxNotify)
	}
}

// eventNotify 事件通知
func (a *notify) wxNotify(c *gin.Context) {
	httpstr := c.Request.URL.RawQuery
	echo := strings.Index(httpstr, "echostr")
	log.Info(" ---------------- wxNotify 收到消息", zap.Any("echo", echo))
	if echo != -1 {
		weixin.VerifyURL(c.Writer, c.Request)
	} else {
		weixin.MsgHandler(c.Writer, c.Request)
	}
	return
}

// UserLogin 用户登录
func (a *notify) UserLogin(ctx context.Context, userId, token string) error {
	type AiQuestionData struct {
		UserId     string `json:"user_id"`
		Timestamp  int64  `json:"timestamp"`
		QuestionId int64  `json:"question_id"`
		IsTrain    bool   `json:"is_train"`
	}

	if userId == "" {
		return fmt.Errorf("用户Id为空")
	}

	type MsgData struct {
		Type    string `json:"type"`
		Content string `json:"content"`
	}

	type Msg struct {
		Msgs    []*MsgData `json:"msgs"`
		AppCode string     `json:"app_code"`
	}

	sendData := &Msg{
		Msgs:    []*MsgData{},
		AppCode: "maya-ai",
	}

	type CustomData struct {
		Text       string `json:"text"`
		BtnText    string `json:"btn_text"`
		BtnLink    string `json:"btn_link"`
		Background string `json:"background"`
		Questioner string `json:"questioner"`
		GuideWords string `json:"guide_words"`
	}

	//  获取数据
	var randomQuestion *model.AiQuestionInfo
	var err error
	result, _ := redis.KV.Get(ctx, fmt.Sprintf("quanxi:ai_question:%v", userId)).Result()
	if result != "" {
		return nil
		// 如果训练过就不弹了
		ret := &AiQuestionData{}
		_ = json.Unmarshal([]byte(result), ret)
		if ret.IsTrain {
			return nil
		}

		// 判断是不是已经答题过
		find, _ := bll.AiConsult.Find(ctx, &model.AiConsultInfoRequest{
			UserId:     &userId,
			QuestionId: &ret.QuestionId,
		})
		if find != nil && find.Id > 0 {
			// 获取当前时间
			now := time.Now()

			// 创建当天午夜 12 点的时间
			// time.Date 参数：年、月、日、时、分、秒、纳秒、时区
			midnight := time.Date(now.Year(), now.Month(), now.Day(), 24, 0, 0, 0, now.Location())

			// 计算时间差
			duration := midnight.Sub(now)

			ret.IsTrain = true
			redis.KV.Set(context.Background(), fmt.Sprintf("quanxi:ai_question:%v", userId), utils.ToJsonString(ret), duration)
			log.Info(fmt.Sprintf("######### 用户已经答过题目更新训练状态 quanxi:ai_question:%v expireTime:%v ret:%v", userId, duration/time.Second, utils.ToJsonString(ret)))
			return nil
		}

		randomQuestion, _ = bll.AiQuestion.Find(ctx, &model.AiQuestionInfoRequest{Id: ret.QuestionId})
	} else {
		// 随机题目推送到主页
		/*randomQuestion, _, err = AiConsult.RandomQuestion(ctx, 1, 0, userId)
		if err != nil {
			log.Error("eventNotify RandomQuestion Exception", zap.Any("err", err), zap.Any("userId", userId))
			return fmt.Errorf("随机题目推送失败")
		}*/

		list := GetQuestionList(ctx, 1, 0)
		sort.Slice(list.List, func(i, j int) bool {
			return list.List[i].Id < list.List[j].Id
		})

		// 获取当前时间
		now := time.Now()

		// 创建当天午夜 12 点的时间
		// time.Date 参数：年、月、日、时、分、秒、纳秒、时区
		midnight := time.Date(now.Year(), now.Month(), now.Day(), 24, 0, 0, 0, now.Location())

		// 计算时间差
		duration := midnight.Sub(now)
		val := redis.KV.Get(ctx, "quanxi:ai_question_flag").Val()
		if val == "" {
			_count, _ := redis.KV.IncrBy(ctx, "quanxi:ai_question_count", 1).Result()
			if duration > 0 {
				redis.KV.Set(ctx, "quanxi:ai_question_flag", _count, duration)
			}
		}

		_count := utils.StrToInt64(val)
		if _count-1 < int64(len(list.List)) {
			randomQuestion = list.List[int(_count-1)]
		} else {
			log.Error("#### 没有可用的题目了 ######")
			randomQuestion = list.List[len(list.List)-1]
		}
	}

	content, _ := json.Marshal(&CustomData{
		Text:       "想要解锁这个咨询室故事吗？",
		BtnText:    "点击了解",
		BtnLink:    fmt.Sprintf("/pages/sub/consult/talk?module=%v&level=%v&question_id=%v&token=%v", randomQuestion.Module, randomQuestion.Level, randomQuestion.Id, token),
		Background: randomQuestion.Content,
		Questioner: randomQuestion.Questioner,
		GuideWords: randomQuestion.GuideWords,
	})
	sendData.Msgs = append(sendData.Msgs, &MsgData{
		Type:    "209",
		Content: string(content),
	})
	err = request.PushData(config.Conf.Env, userId, token, "/api/biz/ai/chat/sendMsg", sendData)
	if err != nil {
		log.Error("eventNotify PushData Exception", zap.Any("err", err), zap.Any("userId", userId))
	} else {
		data, _ := json.Marshal(&AiQuestionData{
			UserId:     userId,
			Timestamp:  time.Now().Unix(),
			QuestionId: randomQuestion.Id,
			IsTrain:    false,
		})

		// 获取当前时间
		now := time.Now()

		// 创建当天午夜 12 点的时间
		// time.Date 参数：年、月、日、时、分、秒、纳秒、时区
		midnight := time.Date(now.Year(), now.Month(), now.Day(), 24, 0, 0, 0, now.Location())

		// 计算时间差
		duration := midnight.Sub(now)

		redis.KV.SetEX(ctx, fmt.Sprintf("quanxi:ai_question:%v", userId), string(data), duration)
		log.Info(fmt.Sprintf("######### 用户每日答题推送成功 quanxi:ai_question:%v expireTime:%v ret:%v", userId, duration/time.Second, string(data)))
	}

	return nil
}

// eventNotify 事件通知
func (a *notify) eventNotify(c *gin.Context) {
	type EventNotify struct {
		Token  string `json:"token"`
		UserId string `json:"user_id"`
		Ops    string `json:"ops"`
		Data   interface{}
	}

	var (
		in  = &EventNotify{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		utils.ResponseOkWithError(c, "参数解析错误")
		return
	}

	switch in.Ops {
	case "ops_userLogin":
		log.Info("--------------- 主页用户登录 ------------------", zap.Any("userId", in.UserId), zap.Any("in", utils.ToJsonString(in)))
		/*type Test struct {
			Test int64 `json:"test"`
		}

		var data Test
		_err := mapstructure.Decode(in.Data, &data)
		if _err != nil {
			fmt.Println("Error:", err)
			return
		}
		return*/
		err = a.UserLogin(c.Request.Context(), in.UserId, in.Token)
		if err != nil {
			utils.ResponseOkWithError(c, err.Error())
			return
		}
		// 企业微信督导师列表编辑
	case "ops_supervisor_change":
		type EditorSupervisor struct {
			SupervisorIds []string `json:"supervisor_ids"`
			Level         int      `json:"level"`
			IsAdd         bool     `json:"is_add"`
			IsCover       bool     `json:"is_cover"`
		}

		var data EditorSupervisor
		if _err := utils.AnyToStruct(in.Data, &data); _err != nil {
			fmt.Println("Error:", err)
			return
		}

		if data.IsCover {
			// 覆盖缓存
			log.Info("######### EventNotify EditorSupervisor 覆盖", zap.Any("data", utils.ToJsonString(data)), zap.Any("err", err))
			go func() {
				defer utils.ExceptionCatch()
				kfId := constant.GetKfId(data.Level)
				userIds, _ := weixin.GetAccountListByKfId(kfId)
				if len(userIds) <= 0 || kfId == "" {
					return
				}

				// 删除
				_ = weixin.RemoveKfAccount(kfId, userIds)

				// 添加客服成员
				if err = weixin.AddKfAccount(kfId, data.SupervisorIds); err != nil {
					log.Error("######### EventNotify AddKfAccount Exception", zap.Any("err", err), zap.Any("data", utils.ToJsonString(data)))
				}

				// 构建缓存
				for kId, v := range constant.KfIdMap {
					userIds, _ = weixin.GetAccountListByKfId(kId)
					if len(userIds) > 0 {
						_ = bll.CacheSupervisorData(v.Level, userIds)
					}
				}
			}()
			utils.ResponseOk(c, nil)
			return
		}

		if data.IsAdd {
			// 加入缓存
			log.Info("######### EventNotify AddSupervisor", zap.Any("data", utils.ToJsonString(data)), zap.Any("err", err))
			go func() {
				defer utils.ExceptionCatch()
				if err = weixin.AddKfAccount(constant.GetKfId(data.Level), data.SupervisorIds); err != nil {
					log.Error("######### EventNotify AddKfAccount Exception", zap.Any("err", err), zap.Any("data", utils.ToJsonString(data)))
				}

				for kfId, v := range constant.KfIdMap {
					userIds, _ := weixin.GetAccountListByKfId(kfId)
					if len(userIds) > 0 {
						_ = bll.CacheSupervisorData(v.Level, userIds)
					}
				}

			}()
		} else {
			go func() {
				defer utils.ExceptionCatch()
				if err = weixin.RemoveKfAccount(constant.GetKfId(data.Level), data.SupervisorIds); err != nil {
					log.Error("######### EventNotify RemoveKfAccount Exception", zap.Any("err", err), zap.Any("data", utils.ToJsonString(data)))
				}

				for kfId, v := range constant.KfIdMap {
					userIds, _ := weixin.GetAccountListByKfId(kfId)
					if len(userIds) > 0 {
						_ = bll.CacheSupervisorData(v.Level, userIds)
					}
				}
			}()
		}

	}

	utils.ResponseOk(c, nil)
	return
}

// vipChargeNtf vip 通知
func (a *notify) vipChargeNtf(c *gin.Context) {
	var (
		in  = &po.VipChargeReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	// 查找用户
	find, err := bll.UserRecord.Find(c.Request.Context(), &model.UserRecordInfoRequest{
		UserId: in.UserId,
	})
	if err != nil {
		c.Error(err)
		return
	}

	nowUnix := time.Now().Unix()
	err = bll.UserRecord.Update(c.Request.Context(), &model.UserRecordUpdateRequest{
		UserId:    &find.UserId,
		CreatedAt: &nowUnix,
	})
	if err != nil {
		c.Error(err)
		return
	}

	utils.ResponseOk(c, nil)
}
